<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title></title>
    <!-- <script src="https://unpkg.com/vue@next"></script> -->
    <script src="https://www.unpkg.com/vue@3.2.47/dist/vue.global.js" type="text/javascript" charset="utf-8"></script>

    <script src="https://www.unpkg.com/axios@1.3.4/dist/axios.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="https://www.unpkg.com/spark-md5@3.0.2/spark-md5.js" type="text/javascript" charset="utf-8"></script>
    <style type="text/css">
        body {
            font-family: Arial;
        }

        form {
            margin: 50px auto;
            width: 600px;
        }

        input[type="button"] {
            cursor: pointer;
        }

        table {

            margin-top: 15px;
            border: 1px solid #ddd;
            border-collapse: collapse;
        }

        table th {
            color: #666;
        }

        table td,
        table th {
            padding: 5px;
            border: 1px solid #ddd;
            text-align: center;
            font-size: 14px;
        }
    </style>
</head>

<body>
    <div id="app">

        <div v-if="isSupportPicker()===false">
            <input type="file" hidden="hidden" id="myfile" />
            <button @click="onSelectUploadFilesFirefox"> 选择文件</button>
        </div>

        <div v-if="isSupportPicker()">
            <button @click="onSelectUploadFiles"> 选择文件</button>
            <button @click="onSelectDir"> 选择文件夹</button>
        </div>

        <div v-if="fileitems.length>0">
            <table id="upload-list">
                <thead>
                    <tr>
                        <th width="35%">文件名</th>
                        <th width="15%">文件类型</th>
                        <th width="15%">文件大小</th>
                        <th width="20%">上传进度</th>
                        <th width="15%">
                            <input type="button" id="upload-all-btn" value="全部上传" @click="onUploadAll">
                        </th>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for="item in fileitems">
                        <td>{{item.filename}}</td>
                        <td>{{item.filetype}}</td>
                        <td>{{displayFileSize(item.file)}}</td>
                        <td>{{item.progress}}</td>
                        <td><button @click="onFileStateChanged(item)"
                                :disabled="getDisabled(item)">{{item.uploadState}}</button></td>
                    </tr>
                </tbody>
            </table>

            {{fileitems}}
        </div>
    </div>

    <script>

        const App = {
            data() {
                return {

                    fileitems: []
                }
            }, methods: {
                displayFileSize: function (file) {
                    if (file === undefined || file.size === undefined) return '';
                    if (file.size / (1024 * 1024) > 1024) return (file.size / (1024 * 1024 * 1024)).toFixed(2) + 'GB';
                    if (file.size / 1024 > 1024) return (file.size / (1024 * 1024)).toFixed(2) + 'MB';
                    if (file.size > 1024) return (file.size / 1024).toFixed(2) + 'KB';
                    return (file.size).toFixed(2) + 'B';
                },
                getDisabled: function (fileitem) {
                    if (fileitem.uploadVal === 3 || fileitem.uploadVal === 2) return 'disabled';
                    return null;
                },
                onGetMd5: function (file) {
                    return new Promise((resolve, reject) => {



                        var chunkSize = 2 * 1024 * 1024;                            // Read in chunks of 2MB
                        var chunks = Math.ceil(file.size / chunkSize);
                        var currentChunk = 0;
                        var spark = new SparkMD5.ArrayBuffer();
                        var fileReader = new FileReader();

                        fileReader.onload = function (e) {

                            spark.append(e.target.result);                   // Append array buffer
                            currentChunk++;

                            if (currentChunk < chunks) {
                                loadNext();
                            } else {

                                resolve(spark.end())
                            }
                        };

                        fileReader.onerror = function (e) {
                            reject(' something went wrong.', e);
                        };

                        function loadNext() {
                            var start = currentChunk * chunkSize,
                                end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;

                            fileReader.readAsArrayBuffer(file.slice(start, end));
                        }

                        loadNext();
                    });
                },
                onGetfileChunkList: async function (fileitem) {

                    console.log("x", fileitem.file);
                    if (fileitem.md5 === '') {
                        fileitem.progress = '文件计算中...';
                        fileitem.md5 = await this.onGetMd5(fileitem.file);
                    }
                    var _file = fileitem.file;
                    const size = 2 * 1024 * 1024;





                    var matchfilename = /([^\\/]+)\.([^\\/]+)/i.exec(fileitem.filename);

                    var suffix = matchfilename[2];

                    let cur = 0;
                    let count = 0;
                    if (fileitem.count > 0) {
                        cur = fileitem.count * size;
                        count = fileitem.count;
                    }
                    const instance = axios.create({
                        baseURL: 'http://localhost:802/',
                        timeout: 36000,
                    });

                    while (cur < _file.size) {

                        if (fileitem.isPaused === 1) return;





                        var end = cur + size;
                        if (end > _file.size) end = _file.size
                        var blob = _file.slice(cur, end);
                        var chunkfilename = matchfilename[1] + ".[" + count + "_" + cur + "]." + suffix;    //    拼装新的文件名，后台通过中间后缀名来定位合并

                        var chunkfile = new File([blob], chunkfilename, { type: _file.type, lastModified: Date.now() });
                        var x = { file: chunkfile, start: cur, end: end, index: count, hash: fileitem.md5, chunkHash: await this.onGetMd5(chunkfile) };
                        fileitem.count = count;
                        var forms = new FormData()

                        forms.append('start', x.start)
                        forms.append('hash', x.hash)
                        forms.append('end', x.end)
                        forms.append('chunkHash', x.chunkHash)
                        forms.append('file', x.file)

                        var uploadChunkFileResult = await instance.post(
                            '/File/BigUploadFile',
                            forms
                        )
                        if (uploadChunkFileResult.status !== 200) throw new Exception('上传失败')
                        fileitem.progress = (x.end * 100 / fileitem.file.size).toFixed(2) + "%";
                        cur += size;
                        count++;
                    }
                    fileitem.uploadVal = 2;
                    fileitem.progress = '文件合并中...';
                    fileitem.uploadState = '文件合并中';
                    var mergeResult = await instance.post(
                        '/File/mergeBigUploadFile?hash=' + fileitem.md5 + "&filecount=" + count
                    )
                    if (mergeResult.data.Tag === 1) {
                        fileitem.uploadVal = 3;
                        fileitem.progress = '上传完成';
                        fileitem.uploadState = '上传完成';
                        console.log('uploadresult', mergeResult.data)
                    } else {
                        throw new Exception('文件合并失败')
                    }

                },
                onUploadAll: function () {

                    for (var item of this.fileitems) {
                        this.onFileStateChanged(item);
                    }
                },
                onFileStateChanged: async function (fileitem) {
                    if (fileitem.isPaused === 0 && fileitem.uploadVal === 0) {
                        fileitem.uploadVal = 1;
                        fileitem.uploadState = '暂停上传';
                        await this.onUploadonefile(fileitem);
                        return;
                    }
                    if (fileitem.isPaused === 0 && fileitem.uploadVal === 1) {
                        fileitem.isPaused = 1;
                        fileitem.uploadState = '恢复上传';
                        await this.onUploadonefile(fileitem);
                        return;
                    }
                    if (fileitem.isPaused === 1 && fileitem.uploadVal === 1) {
                        fileitem.isPaused = 0;
                        fileitem.uploadState = '暂停上传';
                        await this.onUploadonefile(fileitem);
                        return;
                    }
                },
                onUploadonefile: async function (fileitem) {



                    await this.onGetfileChunkList(fileitem);



                },
                isSupportPicker: function () {
                    try {
                        return showOpenFilePicker !== undefined;
                    } catch {

                        return false;
                    }

                },
                onSelectDir: async function () {


                    var dirHandle = await showDirectoryPicker();
                    for await (const [key, value] of dirHandle.entries()) {
                        console.log("value", value)
                        if (value.kind === 'directory') {

                        } else {
                            var xfile = await value.getFile();
                            this.fileitems.push({ filename: key, filetype: xfile.type, file: xfile, uploadVal: 0, uploadState: "开始上传", progress: '', isPaused: 0, md5: '', count: 0 });

                        }
                    }



                },
                onSelectUploadFilesFirefox: async function () {
                    return new Promise(resolve => {


                        var selectedFile = document.getElementById("myfile");
                        selectedFile.onchange = async (x) => {

                            var files = x.target.files;
                            this.counter = files.length;
                            console.log('uploadresult', x)
                            for (var x of files) {
                                this.fileitems.push({ filename: x.name, filetype: x.type, file: x, uploadVal: 0, uploadState: "开始上传", progress: '', isPaused: 0, md5: '', count: 0 });
                            }

                        }

                        selectedFile.click();
                    });

                },
                onSelectUploadFiles: async function () {

                    var files = await showOpenFilePicker({

                        // 可以选择多个图片
                        /* */
                        types: [{
                            description: '图片',
                            accept: {
                                'Images/*': ['.png', '.gif', '.jpeg', '.jpg', '.webp']
                            }
                        }, {
                            description: '视频',
                            accept: {
                                'videos/*': ['.mp4', '.rmvb', '.mkv', '.avi', '.mpeg', '.mov', '.asf', '.3gp']
                            }
                        }, {
                            description: '文档',
                            accept: {
                                'office/*': ['.txt', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.wps']
                            }
                        }
                        ],

                        multiple: true
                    });
                    console.log('picker', files);
                    this.counter = files.length;

                    for (var x of files) {
                        var xfile = await x.getFile();
                        this.fileitems.push({ filename: x.name, filetype: xfile.type, file: xfile, uploadVal: 0, uploadState: "开始上传", progress: '', isPaused: 0, md5: '', count: 0 });
                    }

                }
            }
        };
        Vue.createApp(App).mount('#app');
    </script>
</body>

</html>